/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package reasoner;

import DataTypes.AutoDiaryDataTypes.Accelerometer;
import DataTypes.AutoDiaryDataTypes.PrimaryActivity;
import java.io.File;
import org.encog.neural.networks.BasicNetwork;
import org.encog.persist.EncogDirectoryPersistence;

/**
 *
 * @author thang
 */
public class BasicActivitiesAcce {
    // for distinguish user
    //private String deviceId                             = "samsungGIIFei";
            
    // for storing recognized activities
    //private PrimaryActivity basicAct                    = new PrimaryActivity();
    
    // for data window
    private final int 	DATA_WINDOW_SIZE 		= 5; 
    private double[] 	dataWindow 				= new double[DATA_WINDOW_SIZE];		// data window of A = sprt(X^2 + Y^2 + Z^2) in bound [0, 20] then convert to [0,1] range
    private int 	currentIndex 			= 0;							// current data window index

    // for primActivities window
    private final int 	ACTWINDOW_SIZE			= 7;
    private final int 	ACTWINDOW_OVERLAP		= 2;							// for sliding window
    private String[] 	actWindow				= new String[ACTWINDOW_SIZE];	// window of recognized activities
    private int 	actIndex				= 0;							// current

    private final String[]	activities			= new String[] {"00", "01", "10", "11"};
    private int[]	 actCount				= new int[] {0, 0, 0, 0};		// for calculating dominant activity

    // for loading neural network
    private String 	 nnFileName 				= "WRDS.eg";  					// name of file containing trained Neural Network
    private File 	 nnFile					= null;							// file object
    private BasicNetwork nnWRDS 				= (BasicNetwork)EncogDirectoryPersistence.loadObject(new File("F:/E/study/projects/AutoDiaryNN/Encog/version2/WRDS120619V4-2.eg")); // loaded network
    
    
   
    // -------------------------------------------------------------------------
    // pre-process:
    // - detect primitive activities: walk, run, driving, still
    // - write the result with cpuTimeStamp of last sample in data window to file
    // -------------------------------------------------------------------------
    // calculate euclide distant A = sprt(X^2 + Y^2 + Z^2) in bound [0, 20]
    // package data to window of five A
    // calculate min, max and convert to range [0,1] by dividing to 20
    // load NN
    // set input
    // calculate network
    // get output
    // -------------------------------------------------------------------------
    //public String processData(DataPack dataPackfloat mAcceX, float mAcceY, float mAcceZ, long sensorTimeStamp){
    public PrimaryActivity processAccelerometerData(Accelerometer acceDataPack){

        // recognize activity:
        // calculate euclide distant A = sprt(X^2 + Y^2 + Z^2) in bound [0, 20] then convert to [0,1] range
        double a = Math.sqrt(Math.pow(acceDataPack.getAcceX(), 2) + Math.pow(acceDataPack.getAcceY(), 2) + Math.pow(acceDataPack.getAcceZ(), 2));
        if (a > 20 ){ a = 20;}
        a = a/20;

        // package data to window of five As
        dataWindow[currentIndex] = a;

        // activity recognized
        String strActivity = "";
        // result of window reasoning
        String dominantAct = "";
        
        // final result object
        PrimaryActivity basicAct = null;

        // if window is loaded all five samples then calculate NN 
        if(currentIndex == (DATA_WINDOW_SIZE - 1)) {
            double[] wMinMax = minMaxAverage(dataWindow);
            if (wMinMax == null){return null;}

            // set network input and calculate
            // construct network input = (min, max - min)
            double[] nnInput = new double[2];
            nnInput[0] = wMinMax[0];			// min
            nnInput[1] = wMinMax[1] - wMinMax[0];	// max - min
            double[] nnOutput = new double[2];
            nnWRDS.compute(nnInput, nnOutput);

            // get nn output
            for (double d: nnOutput){
                    strActivity += Math.round(d);
            }

            // put in window reasoning - dominant calculator
            dominantAct = windowReasoning(strActivity.trim());

            // set current activity to the dominant one
            if( dominantAct != null && dominantAct.trim().length() > 0 ){
                basicAct = new PrimaryActivity();
                basicAct.setActivityCode(dominantAct.trim());
                // suppose sensortimestamp is close to the system time when processing the sensor data
                basicAct.setSensorTimeStamp(acceDataPack.getCpuTimeStamp());
                basicAct.setDevice_id(autodiaryserver.Declare.DEVICE_ID);
            }
            
            // put in db
            
            /*
            activityPack.setActivityCode(strActivity.trim());
            // suppose sensortimestamp is close to the system time when processing the sensor data
            activityPack.setSensorTimeStamp(acceDataPack.getCpuTimeStamp());

            // store in sqlite 
            sensorDb.storeData(activityPack);
            // write activities to file
            writeToFile(activityPack);
            */

            // reset index
            currentIndex = 0;

        }else{	// if window is nor fully loaded
                // increase index to load next samples
                currentIndex++;
                // no activity is recognized
                strActivity += "null";
                dominantAct += "null";
        }

        //return result;
        return basicAct;
        
    }

    // -------------------------------------------------------------------------
    // return min, max, average of an input array
    // result[0] = min, result[1] = max, result[2] = average
    // -------------------------------------------------------------------------
    public double[] minMaxAverage(double[] arr){
        double[] result = null;
        
        // check input null
        if (arr.length < 1){return result;
        } else{ 
        	result = new double[3];
        }
        
        result[0]       = arr[0];	// init min
        result[1]       = arr[0];	// init max
        result[2]   	= arr[0];	// init average
        double sum      = arr[0];	// init sum
        
        for (int i = 1; i < arr.length; i++) {
            if (result[0] > arr[i]){ result[0] = arr[i];}
            if (result[1] < arr[i]){ result[1] = arr[i];}
            sum += arr[i];
        }
        
        result[2] = sum/(arr.length);

        return result;
    }

    /* -------------------------------------------------------------------------
    *
    * -------------------------------------------------------------------------
    */
    public String windowReasoning(String actCode){
        // package recognized activities to window of 7
        actWindow[actIndex] = actCode;

        // activity recognized
        String act = "";
        
        // if window is loaded all 7 samples then calculate dominant activity 
        if(actIndex == (ACTWINDOW_SIZE - 1)){
            // calculate dominant activity
            act = dominantAct();
            // slide window
            slideWindow();

        }else{	// if window is nor fully loaded
                // increase index to load next samples
                actIndex++;
                // no activity is recognized
                act = "";
        }

        return act;
    }

    // caculate the dominant activity which appears most in the activities window
    public String dominantAct(){
    	int maxCount	= 0;	// appearance time of dominant activity
    	int maxIndex 	= 0;	// dominant activity index
    	
    	for (int i = 0; i < actWindow.length; i++){
            for (int j = 0; j < activities.length; j++){
                if (actWindow[i].trim().equalsIgnoreCase(activities[j].trim())){
                    actCount[j]++;
                    if (maxCount < actCount[j]){
                            maxCount = actCount[j];
                            maxIndex = j;
                    }
                    break;
                }
            }
    	}
        return activities[maxIndex];
    }
    
    public void slideWindow(){
    	for (int i = 0; i < ACTWINDOW_OVERLAP; i++){
    		actWindow[i] = actWindow[ACTWINDOW_SIZE - ACTWINDOW_OVERLAP + i]; 
    	}
		actIndex = ACTWINDOW_OVERLAP;
    }

}
